﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Automation;

namespace LEET.LEETCommon.WidgetLookup
{
    public class Lookup<T>
    {
        bool Frozen;
        Node<T> Root;
        Node<T> Current;

        public Lookup(T root)
        {
            Frozen = false;
            Root = new Node<T>(root);
            Current = Root;
        }

        internal void Complete()
        {
            Frozen = true;
        }

        public T Location { get { return Current.Value; } }

        internal void Fail(List<T> options)
        {
            if (Frozen) return;
            Current.OptionsAtDeadEnd = options;
            Current = Current.Parent;
        }

        internal void Include(T possible)
        {
            if (Frozen) return;
            Current = Current.AddChild(possible);
        }

        public bool Failed { get { return !Frozen; } }

        public delegate string ToStr<S>(S s);
        public string ToString(ToStr<T> func)
        {
            StringBuilder buf = new StringBuilder();
            toStr(buf, 0, func, Root);
            return buf.ToString();
        }
        
        private void toStr(StringBuilder buf, int tabCount, ToStr<T> encode, Node<T> node)
        {
            for (int i = 0; i < tabCount; i++) buf.Append("|\t");
            buf.Append(encode(node.Value));
            buf.Append(Environment.NewLine);
            if (node.Children.Count == 0)
            {
                foreach(T t in node.OptionsAtDeadEnd)
                {
                    for (int i = 0; i <= tabCount; i++) buf.Append("|\t");
                    buf.Append(encode(t));
                    buf.Append(Environment.NewLine);
                }
            }
            else
            {
                foreach (Node<T> child in node.Children)
                    toStr(buf, tabCount + 1, encode, child);
            }
        }
        
    }

    class Node<T>
    {
        T val;

        internal Node<T> Parent { get; private set; }
        internal List<Node<T>> Children { get; private set; }

        internal Node(T t)
        {
            val = t;
            Children = new List<Node<T>>();
        }

        internal T Value { get { return val; } }

        internal Node<T> AddChild(T t)
        {
            Node<T> node = new Node<T>(t);
            node.Parent = this;
            Children.Add(node);
            return node;
        }

        internal List<T> OptionsAtDeadEnd { get; set; }
    }
}
